/**************************************************************/
/*  This file is licensed from, and is a trade secret of:     */
/*                                                            */
/*    Mercury Computer Systems, Incorporated                  */
/*    199 Riverneck Road                                      */
/*    Chelmsford, Massachusetts 01824-2820                    */
/*    United States of America                                */
/*    Telephone + 1 978 256-1300                              */
/*                                                            */
/*  Refer to your Software License Agreement for provisions   */
/*  on use, duplication, or disclosure.                       */
/*  US. Government users and prime contractors are also       */
/*  governed by the following Data Rights Notice:             */
/*  Use, duplication or disclosure by the US. Government is   */
/*  subject to the provisions set forth in FAR 52.227-14 for  */
/*  restricted rights or other agency data rights provisions  */
/*  on commercial software and documentation, as applicable.  */
/*                                                            */
/*  This file: (a) was developed at private expense, and no   */
/*  part was developed with government funds, (b) is a        */
/*  trade secret of Mercury Computer Systems, Inc. for the    */
/*  purposes of the Freedom of Information Act, (c) is        */
/*  "commercial computer software" subject to limited         */
/*  utilization as provided in the above noted Software       */
/*  License Agreement and (d) is in all respects data         */
/*  belonging exclusively to Mercury Computer Systems, Inc..  */
/*                                                            */
/**************************************************************/

/******************************************************************/
/* Copyright (c) 1999-2003, Mercury Computer Systems, Inc.,       */
/* Chelmsford MA.,and all third party embedded software sources.  */
/* All rights reserved under the Copyright laws of US. and        */
/* international treaties.                                        */
/*                                                                */
/* Patent Pending                                                 */
/******************************************************************/


//$COPYRIGHT_END


#include "rf.h"
#include "SceOsMisc.h"

using namespace std;

/*
 * Process data in small chunks instead of 1 big one or single samples.
 */

const int SampleBlock = 512;

extern "C" {
  RF_EXPORT
  POA_CF::Resource *
  CreateRfChannelEmulator (const char * identifier)
  {
    RfChannelEmulator * Modulator;

    if (RfChannelEmulator::Create (Modulator, identifier) != success) {
      return 0;
    }

    return (POA_CF::Resource *) Modulator;
  }
}

status
RfChannelEmulator::Create (RfChannelEmulator *& handle,
			   const char * identifier)
{
  RfChannelEmulator *Temp = new RfChannelEmulator (identifier);

  if (!Temp) {
    handle = 0;
    return fail;
  }

  handle = Temp;
  return success;
}

RfChannelEmulator::RfChannelEmulator (const char * identifier)
  : CF__Resource_impl (identifier),
    m_threadrunning (false),
    m_bStop (false)
{
  unsigned int input_buffer_size;
  unsigned int output_buffer_size;

  // define ports
  input_buffer_size = 4096;
  m_rfcomplexin = new ComplexShortInPort_impl (input_buffer_size);

  output_buffer_size = 4096;
  m_output = new CMPLX_INT16 [output_buffer_size];
  m_rfcomplexout = new ComplexShortOutPort_impl (m_output, output_buffer_size);
}

RfChannelEmulator::~RfChannelEmulator ()
{
  // destructor
  delete m_rfcomplexin;
  delete m_rfcomplexout;
  delete m_output;
}

CORBA::Object_ptr
RfChannelEmulator::getPort (const CORBA::Char * name)
  throw (CORBA::SystemException, CF::PortSupplier::UnknownPort)
{
  string temp (name);

  if (temp == "RF_In") {
    return m_rfcomplexin->getPort();
  }
  else if (temp == "RF_Out") {
    return m_rfcomplexout->getPort();
  }
  else {
    throw CF::PortSupplier::UnknownPort();
  }
}  //RfChannelEmulator::getPort()

void
RfChannelEmulator::start()
  throw (CORBA::SystemException, CF::Resource::StartError)
{
  if (m_threadrunning) {
    return;
  }

  m_threadrunning = true;
  m_thread.start(RunWorker, (void *)this);
  CF__Resource_impl::start();
} // RfChannelEmulator::start()

void
RfChannelEmulator::stop()
  throw (CORBA::SystemException, CF::Resource::StopError)
{
  m_bStop = true;
  m_threadrunning = false;
  m_thread.detach();

} // RfChannelEmulator::stop()

status
RfChannelEmulator::Init ()
{
#ifdef MCS_VERBOSE
  std::cout << "RfChannelEmulator: Initializing." << std::endl;
#endif

  /*
   * Property UUIDs (from .prf.xml)
   *
   * <simple id="DCE:4214f7ec-0351-4b2a-97a2-d2d5789dffae" type="long" name="Noise_Power_dB" mode="readwrite">
   *   <value>38</value>
   *   <kind kindtype="configure" />
   * </simple>
   */

  try {
    int index;
    CORBA::Short temp;
    // prop_name - "Noise_Power_dB"; 
    const char * prop_name = "DCE:4214f7ec-0351-4b2a-97a2-d2d5789dffae";
    index = GetPropertyIndex (prop_name);

    if (index < 0) {
      return fail;
    }

    if (GetPropertyValue (index, &temp)) {
      return fail;
    }
  }
  catch (...) {
    return fail;
  }

  // NOTE: Input power from MSK_Mod is 42.13dB

  // initialize AWGN parameters
  m_sigma = 10.0f;
  return success;
}

// Generic thread OS signature which calls component specific thread function.
void
RfChannelEmulator::RunWorker (void * param)
{
  RfChannelEmulator * component = (RfChannelEmulator *) param;

#ifdef MCS_VERBOSE
  std::cout << "RfChannelEmulator: Component is running." << std::endl;
#endif

  component->RunLoop();

#ifdef MCS_VERBOSE
  std::cout << "RfChannelEmulator: Component is stopping." << std::endl;
#endif
}

// Inner loop function that checks for a stop command.
void
RfChannelEmulator::RunLoop ()
{
  m_bStop = false;

  // initialize run conditions
  Init ();

  while (!m_bStop) {
    Run ();
  }

  m_rfcomplexin->ReleaseDataBuffer ();
}

void
RfChannelEmulator::ComplexAWGN (CMPLX_INT16 * rf_in,
				CMPLX_INT16 * rf_out,
				unsigned int num_samples)
{
  /*
   * Complex additive white Gaussian noise.
   *
   * This function approximates an AWGN channel by summing Bernoulli trials
   * to produce a binomial approximation to a gaussian RV.
   */

  unsigned int i, j, N=64;
  double scaling_factor = double(m_sigma) / sqrt( double(N)/4 );
  signed int n_I, n_Q;

  for (i=0; i<num_samples; i++) {
    n_I = 0;
    n_Q = 0;

    /*
     * Produces 2 binomial RVs, with gaussian approximations
     * with mean N/2 and variance N/4.
     */

    for (j=0; j<N; j++) {
      // Add N Bernoulli trials, p=0.5.
      n_I += rand () % 2;
      n_Q += rand () % 2;
    }

    // adjust mean and variance.
    n_I = (signed int) ((n_I - N/2) * scaling_factor);
    n_Q = (signed int) ((n_Q - N/2) * scaling_factor);

    rf_out[i] = rf_in[i] + CMPLX_INT16 (n_I, n_Q);
  }
}

void
RfChannelEmulator::ComplexAWUN (CMPLX_INT16 * rf_in,
				CMPLX_INT16 * rf_out,
				unsigned int num_samples)
{
  /*
   * Complex additive white uniform noise.
   *
   * Variance of a symmetric uniform RV on the interval[-a,a] is (a^2)/3.
   */

  signed int n_I, n_Q;
  unsigned int i;
  float var = m_sigma;
  int a = (var > 0.0) ? (int) sqrt (var*3) : 1;

  for (i=0; i<num_samples; i++) {
    n_I = (rand() % (2*a)) - a;
    n_Q = (rand() % (2*a)) - a;

    rf_out[i] = rf_in[i] + CMPLX_INT16 (n_I, n_Q);
  }
}

// Inner loop method that performs component business logic.
status
RfChannelEmulator::Run ()
{
  m_input_count = m_rfcomplexin->GetData (&m_input);

  if (m_input_count == 0) {
    return success;
  }

  // transparent channel
  m_rfcomplexout->pushData (m_input, m_input_count);
  m_rfcomplexin->ReleaseDataBuffer ();
  return success;
}  // RfChannelEmulator::Run()
